package com.pan.common.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;

/**
 * api线程池异步调用工具类
 *
 * @author cpl_wwl
 */
@Component
@Slf4j
public class ApiAsyncCallUtil implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext param) throws BeansException {
        applicationContext = param;
    }

    /**
     * 通用异步调用api
     *
     * @param apiType        接口类型, demo: GoodsApi.class
     * @param methodName     方法名
     * @param args           可变参数, 调用方法所需参数
     */
    @Async("apiAsyncCall")
    public CompletableFuture<Object> commonAsyncCallApi(Class<?> apiType,
                                                        String methodName,
                                                        Object... args) {
        Object api = applicationContext.getBean(apiType);
        try {
            Method[] methods = api.getClass().getDeclaredMethods();
            Method matchMethod = null;
            for (Method method : methods) {
                if (method.getParameterCount() == args.length && method.getName().equals(methodName)) {
                    Class<?>[] types = method.getParameterTypes();
                    if (types.length == 0) {
                        matchMethod = method;
                        break;
                    } else {
                        boolean allMatch = true;
                        for (int i = 0; i < types.length; i++) {
                            if (!types[i].isAssignableFrom(args[i].getClass())) {
                                allMatch = false;
                                break;
                            }
                        }
                        if (allMatch) {
                            matchMethod = method;
                            break;
                        }
                    }
                }
            }
            if (matchMethod == null) {
                String errMsg = apiType.getName() + "不存在方法" + methodName;
                throw new NoSuchMethodException(errMsg);
            }
            Object result = matchMethod.invoke(api, args);
            return CompletableFuture.completedFuture(result);
        } catch (NoSuchMethodException e) {
            log.error(e.getMessage(), e);
            throw new IllegalStateException(e.getMessage(), e);
        } catch (Exception e) {
            String errMsg = String.format("%s.%s(%s)方法反射调用失败：", apiType.getName(), methodName, JSON.toJSON(args));
            log.error(errMsg, e);
            throw new IllegalStateException(errMsg, e);
        }
    }



    /**
     * 线程池异步调用CustDocDefApi.findByCustDocCodeAndCustDocDefCode获取自定义档案
     *
     * @param custDocCode    自定义档案编码
     */
    @Async("apiAsyncCall")
    public CompletableFuture<String> asyncFindByCustDocCodeAndCustDocDefCode(String custDocCode) {

        log.info("asyncFindByCustDocCodeAndCustDocDefCode--start:{}",custDocCode);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("asyncFindByCustDocCodeAndCustDocDefCode--end:{}",custDocCode);
        return CompletableFuture.completedFuture("custDocCode"+custDocCode);
    }
}
